#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>
using namespace std;

class TinyMatrix
{
public:
    int x, y;
public:
    float** matrix;

public:
    TinyMatrix(int x, int y)
    {
        this->x = x;
        this->y = y;
        matrix = new float*[x];
        for (int i =0; i!=x; ++i)
        {
            matrix[i] = new float[y];
            for (int j = 0; j != y; ++j)
            {
                matrix[i][j] = 0;
            }
        }
    }
public:
    TinyMatrix(int x, int y, float * vec)
    {
        this->x = x;
        this->y = y;
        matrix = new float*[x];
        for (int i =0; i!=x; ++i)
        {
            matrix[i] = new float[y];
            for (int j = 0; j != y; ++j)
            {
                matrix[i][j] = vec[j];
            }
        }
    }
public:
    TinyMatrix(TinyMatrix * mat)
    {
        this->x = mat->x;
        this->y = mat->y;
        matrix = new float*[x];
        for (int i =0; i!=x; ++i)
        {
            matrix[i] = new float[y];
            for (int j = 0; j != y; ++j)
            {
                matrix[i][j] = mat->Get(i,j);
            }
        }
    }
public:
    static TinyMatrix* Diag(int n)
    {
        TinyMatrix * mat = new TinyMatrix(n, n);
        for (int i =0; i!=n; ++i)
        {
            mat->Set(i,i, 1);
        }
        return mat;
    }
public:
    ~TinyMatrix()
    {
        for (int i =0; i!=x; ++i)
        {
            delete matrix[i];
        }
        delete matrix;
    }
public:
    void Set(int m, int n, float value)
    {
        matrix[m][n] = value;
    }
public:
    void Add(int m, int n, float value)
    {
        matrix[m][n] += value;
    }
public:
    float Get(int m, int n)
    {
        return matrix[m][n];
    }

public:
    TinyMatrix* Transform()
    {
        TinyMatrix* trans = new TinyMatrix(y, x);
        for (int i =0; i!=x; ++i)
        {
            for (int j =0; j!=y; ++j)
            {
                trans->Set(j, i, Get(i, j));
            }
        }
        return trans;
    }
public:
    void AddVector(int line, float * vec, float rate = 1)
    {
        for (int i=0; i!=this->y; ++i)
        {
            matrix[line][i] += vec[i] * rate;
        }
    }

public:
    void MinusVector(int line, float * vec, float rate = 1)
    {
        AddVector(line, vec, -rate);
    }
public:
    float Det()
    {
        TinyMatrix * mat = new TinyMatrix(this);
        for (int i =0; i!= this->x; ++i)
        {
            if (mat->Get(i,i) ==0)
            {
                int j =i+1;
                while (j != this->x && mat->Get(j,i)==0)
                {
                    ++j;
                }
                if (j == this->x)
                {
                    delete mat;
                    return 0;
                }
                mat->AddVector(i, mat->matrix[j]);
            }
            for (int j = i + 1; j!=this->x; ++i)
            {
                mat->MinusVector(j, mat->matrix[i], mat->Get(j,i)/mat->Get(i,i));
            }
        }
        float result = 0;
        for (int i = 0; i != mat->x; ++i)
        {
            result *= mat->Get(i,i);
        }
        delete mat;
        return result;
    }
public:
    TinyMatrix * Inverse()
    {
        TinyMatrix * mat = new TinyMatrix(this);
        TinyMatrix * result = TinyMatrix::Diag(mat->x);
        for (int i =0; i!= this->x; ++i)
        {
            if (mat->Get(i,i) ==0)
            {
                int j =i+1;
                while (j != this->x && mat->Get(j,i)==0)
                {
                    ++j;
                }
                result->AddVector(i, result->matrix[j]);
                mat->AddVector(i, mat->matrix[j]);
            }
            for (int j = i + 1; j!=this->x; ++i)
            {
                result->MinusVector(j, result->matrix[i], mat->Get(j,i)/mat->Get(i,i));
                mat->MinusVector(j, mat->matrix[i], mat->Get(j,i)/mat->Get(i,i));
            }
        }
        return result;
    }

public:
    static TinyMatrix* Times(TinyMatrix* mat1, TinyMatrix* mat2)
    {
        TinyMatrix* times = new TinyMatrix(mat1->x, mat2->y);
        for (int i =0; i !=mat1->x; ++i)
        {
            for (int k =0; k!=mat2->y; ++k)
            {
                times->Set(i, k, 0);
                for (int j =0; j!=mat1->y; ++j)
                {
                    times->Add(i, k, mat1->Get(i,j) * mat2 ->Get(j, k));
                }
            }
        }
        return times;
    }
public:
    TinyMatrix* Times(TinyMatrix* mat)
    {
        return Times(this, mat);
    }
public:
    static TinyMatrix* Add(TinyMatrix* v1, TinyMatrix *v2, float rate = 1)
    {
        TinyMatrix * result = new TinyMatrix(v1);
        for (int i = 0; i != result->x; ++i)
        {
            for (int j = 0; j!= result->y; ++j)
            {
                result->matrix[i][j] += v2->matrix[i][j] * rate;
            }
        }
        return result;
    }
public:
    static TinyMatrix* Minus(TinyMatrix* v1, TinyMatrix *v2, float rate = 1)
    {
        return Add(v1,v2,-rate);
    }
};

class Sample
{
public:
    TinyMatrix* feature;
public:
    int label;
public:
    Sample(TinyMatrix * feature, int label = 0)
    {
        this->feature = feature;
        this->label = label;
    }
};
void TestMatrix();
void ReadTrainData();
vector<Sample*> * list = new vector<Sample*>();
int main()
{
    TestMatrix();
    //ReadTrainData();
    return 0;
}

void TestMatrix()
{
    //cout<<atan(1)*4<<endl;
}
void ReadTrainData()
{
    FILE *file = fopen("train.txt", "r");

    if (file == NULL)
    {
        printf("File not found\n");
    }
    float x, y;
    int label;
    while (feof(file) == 0)
    {
        x=0;
        y=0;
        label = 0;
        fscanf(file, "%f %f %d\n", &x, &y, &label);
        list->push_back(new Sample(new TinyMatrix(1, 2, new float[2] {x, y}),label));
    }
    fclose(file);

//	for (int i = 0; i != list->size(); ++i){//
//        printf("%f %f %d\n", (*list)[i]->x, (*list)[i]->y, (*list)[i]->label);
//	}
    printf("%d", list->size());
}

int m = 3;
float* clast;
TinyMatrix** mulast;
TinyMatrix** sigmalast;
float* cnow;
TinyMatrix** munow;
TinyMatrix** sigmanow;

void train()
{
    clast =  new float[m];
    cnow = new float[m];

    int sizeall = list->size();
    float** gama = new float*[m];
    float** gauss = new float*[m];

    for (int i =0; i!= m; ++i)
    {
        gama[i] = new float[sizeall];
        gauss[i] = new float[sizeall];

        for (int j = 0; j!= sizeall;++j){
            gama[i][j] = 0;
            gauss[i][j] = 0;
        }
    }

    for (int j =0; j!= m; ++j)
    {
        TinyMatrix * mu = mulast[j];
        TinyMatrix * sigma = sigmalast[j];

        float det = sigma->Det();
        det = sqrt(det);
        float pi = atan(1) * 4;
        pi = pow(pi*2, 2/2);

        TinyMatrix * inverse =  sigma->Inverse();
        for (int i = 0; i!=sizeall; ++i)
        {
            Sample * x = (*list)[i];
            TinyMatrix * xfea = x->feature;
            TinyMatrix * tmp1 = TinyMatrix::Minus(xfea, mu);
            TinyMatrix * tmp2 = tmp1->Transform();
            TinyMatrix * tmp3 = TinyMatrix::Times(tmp2, inverse);
            TinyMatrix * tmp4 = TinyMatrix::Times(tmp3, tmp1);
            float value = tmp4->matrix[0][0]* (-0.5);
            float expvalue = exp(value);
            float N = 1/(pi* det) * expvalue;

            delete tmp1;
            delete tmp2;
            delete tmp3;
            delete tmp4;
        }
    }
}
